package com.xvyy.tingshu.search.runnable;

import com.xvyy.tingshu.search.factory.ScheduledTaskThreadFactory;
import com.xvyy.tingshu.search.service.impl.ItemServiceImpl;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * ClassName: RebuildDistributedBloomFilterRunnable
 * Package: com.xvyy.tingshu.search.runnable
 *
 * @Description: 重建分布式布隆过滤器任务
 * @Author: xvyy
 * @Create: 2025/2/7 - 19:46
 * @Version: v1.0
 */
public class RebuildDistributedBloomFilterRunnable implements Runnable {

    Logger logger = LoggerFactory.getLogger(getClass());
    private RedissonClient redissonClient;
    private ItemServiceImpl itemService;
    private StringRedisTemplate stringRedisTemplate;

    public RebuildDistributedBloomFilterRunnable(RedissonClient redissonClient, ItemServiceImpl itemService, StringRedisTemplate stringRedisTemplate) {
        this.redissonClient = redissonClient;
        this.itemService = itemService;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    /**
     * 重建分布式布隆过滤器
     * 删除和新载原子操作
     */
    @Override
    public void run() {
        logger.info("开始重建分布式布隆过滤器");
        // 1. 创建一个新的布隆过滤器
        RBloomFilter<Object> newBloomFilter = redissonClient.getBloomFilter("albumIdBloomFilter:new");
        newBloomFilter.tryInit(1000000L, 0.03);// 预计插入100万数据，误差率3%
        // 2. 获取最新的专辑id列表
        List<Long> albumInfoIdList = itemService.getAlbumInfoIdList();
        if (!CollectionUtils.isEmpty(albumInfoIdList)) {
            // 3. 将albumIdList添加到新的布隆过滤器中
            for (Long albumInfoId : albumInfoIdList) {
                newBloomFilter.add(albumInfoId);
            }
            logger.info("新布隆过滤器初始化完成，数据量：{}", newBloomFilter.count());
        }
/*        // 4. 将旧的布隆过滤器删除
        stringRedisTemplate.delete("albumIdBloomFilter");
        stringRedisTemplate.delete("{albumIdBloomFilter}:config");
        // 5. 将新的布隆过滤器重命名
        stringRedisTemplate.rename("albumIdBloomFilter", "albumIdBloomFilter:new");*/
        // 4. 引入Lua脚本，保证操作的原子性
        String script = " redis.call(\"del\",KEYS[1])" +
                "  redis.call(\"del\",KEYS[2])" +
                "  redis.call(\"rename\",KEYS[3],KEYS[1])" +
                "  redis.call(\"rename\",KEYS[4],KEYS[2]) return 1";
        List<String> asList = Arrays.asList("albumIdBloomFilter", "{albumIdBloomFilter}:config", "albumIdBloomFilter:new", "{albumIdBloomFilter:new}:config");
        Long execute = stringRedisTemplate.execute(new DefaultRedisScript<>(script, Long.class), asList);
        if (execute == 1) {
            logger.info("新布隆过滤器重载完成");
        }else {
            logger.info("新布隆过滤器重载失败，继续使用旧布隆过滤器");
        }

        // 5. 接着延时执行下一次重建任务 （延时任务嵌套自己实现定时任务）
/*        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        // this：当前new RebuildDistributedBloomFilterRunnable(redissonClient, itemService, stringRedisTemplate)
        scheduledExecutorService.schedule(this, 1L, TimeUnit.MINUTES);//延迟1分钟执行*/
        ScheduledTaskThreadFactory.getInstance().executeTaskSchedule(this, 1L, TimeUnit.MINUTES);//测试用
//        ScheduledTaskThreadFactory.getInstance().executeTaskSchedule(this, 7L, TimeUnit.DAYS);//生产用
//         ScheduledTaskThreadFactory.getInstance().executeTaskScheduleWithFixedDelay(this, 7L, 1L, TimeUnit.DAYS);
    }
}
